<?php
/**
 * ExtHTMLParserNode class file
 *
 * @author TrueSoftware B.V. (The Netherlands)
 * @link http://www.ext4yii.com
 * @copyright Copyright 2007-2010 TrueSoftwareB.V. all rights reserved.
 * @license http://www.ext4yii.com/license/
 *          EVALUATION VERSION - NOT FOR COMMERCIAL USE OR DISTRIBUTION.
 * @version 0.7.2
 */
 
 
/* Version: 1.11 ($Rev: 103 $)
 * Website: http://sourceforge.net/projects/simplehtmldom/
 * Author: S.C. Chen <me578022@gmail.com>
 * Acknowledge: Jose Solorzano (https://sourceforge.net/projects/php-html/)
 * Contributions by:
 *      Yousuke Kumakura (Attribute filters)
 *      Vadim Voituk (Negative indexes supports of "find" method)
 *      Antcs (Constructor with automatically load contents either text or file/url)
 *      Licensed under The MIT License
 *      Redistributions of files must retain the above copyright notice.
 *
 * This file and its contents is an specialized version of ExtHTMLParserDom that is
 * modified to be used in ext4yii framework.
*/

class ExtHTMLParserNode
{
    public $nodetype = HDOM_TYPE_TEXT;
    public $tag = 'text';
    public $walked = false;
    public $exttag = null;
    public $extctl = null;
    public $attr = array();
    public $styles=array();
    public $classes=array();
    public $children = array();
    public $nodes = array();
    public $parent = null;
    public $_ = array();
    private $dom = null;

    /* this is the prop:* tag when parsing the controls.
     * We need a way to know in what type of a prop:* element
     * this node finds itself. this is used to skip or create a container
     * for the controls. see: ExtWidget->createContainer.
     *
     * The value of this method is set in ExtWidget->parseNodeWithTag and
     * used in AstWalker->walk
    */
    public $virtualParent = null;

    public function findPropertyByName($name)
    {
        if(count($this->children) == 0)
            return null;
        $prop = 'prop:' . strtolower($name);
        foreach($this->children as $item)
        {
            if($item->nodetype==HDOM_TYPE_EXTPROP && strtolower($item->tag)==$prop)
                return $item;
        }
        return null;
    }

    public function findNodeByTypeAndTag($type,$tag)
    {
        if(count($this->children) == 0)
            return null;
        foreach($this->children as $item)
        {
            if($item->nodetype==$type && $item->tag==$tag)
                return $item;
        }
        return null;
    }

    public function shiftUp()
    {
        $this->outertext = trim($this->innertext);
    }

    function __construct($dom)
    {
        $this->dom = $dom;
        $dom->nodes[] = $this;
    }

//    disabled for testing on XDebug
//    function __destruct()
//    {
//        $this->clear();
//    }

    function __toString()
    {
        return $this->outertext();
    }

    // clean up memory due to php5 circular references memory leak...
    function clear()
    {
        $this->dom = null;
        $this->nodes = null;
        $this->parent = null;
        $this->children = null;
    }

    // returns the first child of node
    function first_child()
    {
        if (count($this->children)>0) return $this->children[0];
        return null;
    }

    // get dom node's inner html
    function innertext()
    {
        if (isset($this->_[HDOM_INFO_INNER])) return $this->_[HDOM_INFO_INNER];
        if (isset($this->_[HDOM_INFO_TEXT])) return $this->dom->restore_noise($this->_[HDOM_INFO_TEXT]);

        $ret = '';
        foreach($this->nodes as $n)
            $ret .= $n->outertext();
        return $ret;
    }

    // get dom node's outer text (with tag)
    function outertext()
    {
        /*
        if($this->shiftup === true)
            return null;
        */

        if ($this->tag==='root') return $this->innertext();

        // trigger callback
        if ($this->dom->callback!==null)
            call_user_func_array($this->dom->callback, array($this));

        if (isset($this->_[HDOM_INFO_OUTER])) return $this->_[HDOM_INFO_OUTER];
        if (isset($this->_[HDOM_INFO_TEXT])) return $this->dom->restore_noise($this->_[HDOM_INFO_TEXT]);

        // render begin tag
        $ret = $this->dom->nodes[$this->_[HDOM_INFO_BEGIN]]->makeup();

        // render inner text
        if (isset($this->_[HDOM_INFO_INNER]))
            $ret .= $this->_[HDOM_INFO_INNER];
        else
        {
            foreach($this->nodes as $n)
                $ret .= $n->outertext();
        }

        // render end tag
        if(isset($this->_[HDOM_INFO_END]) && $this->_[HDOM_INFO_END]!=0)
            $ret .= '</'.$this->tag.'>';
        return $ret;
    }

    // build node's text with tag
    function makeup()
    {
        $error_rep_level = error_reporting();
        error_reporting(E_ALL ^ E_NOTICE);

        // text, comment, unknown
        if (isset($this->_[HDOM_INFO_TEXT]))
        {
            error_reporting($error_rep_level);
            return $this->dom->restore_noise($this->_[HDOM_INFO_TEXT]);
        }

        $ret = '<'.$this->tag;
        $i = -1;

        if(count($this->styles) != 0)
            $this->attr[' style'] = implode(';',$this->styles);

        if(count($this->classes) != 0)
            $this->attr[' class'] = implode(' ',$this->classes);


        foreach($this->attr as $key=>$val)
        {
            ++$i;

            // skip removed attribute
            if ($val===null || $val===false)
                continue;

            $ret .= $this->_[HDOM_INFO_SPACE][$i][0];
            //no value attr: nowrap, checked selected...
            if ($val===true)
                $ret .= $key;
            else
            {
                switch($this->_[HDOM_INFO_QUOTE][$i])
                {
                    case HDOM_QUOTE_DOUBLE: $quote = '"';
                        break;
                    case HDOM_QUOTE_SINGLE: $quote = '\'';
                        break;
                    default: $quote = '';
                }
                $ret .= $key.$this->_[HDOM_INFO_SPACE][$i][1].'='.$this->_[HDOM_INFO_SPACE][$i][2].$quote.$val.$quote;
            }
        }
        $ret = $this->dom->restore_noise($ret);
        error_reporting($error_rep_level);
        return $ret . $this->_[HDOM_INFO_ENDSPACE] . '>';
    }

    function __get($name)
    {
        if (isset($this->attr[$name])) return $this->attr[$name];
        switch($name)
        {
            case 'outertext': return $this->outertext();
            case 'innertext': return $this->innertext();
            case 'plaintext': return $this->text();
            case 'xmltext': return $this->xmltext();
            default: return array_key_exists($name, $this->attr);
        }
    }

    function __set($name, $value)
    {
        switch($name)
        {
            case 'outertext': return $this->_[HDOM_INFO_OUTER] = $value;
            case 'innertext':
                if (isset($this->_[HDOM_INFO_TEXT])) return $this->_[HDOM_INFO_TEXT] = $value;
                return $this->_[HDOM_INFO_INNER] = $value;
        }
        if (!isset($this->attr[$name]))
        {
            $this->_[HDOM_INFO_SPACE][] = array(' ', '', '');
            $this->_[HDOM_INFO_QUOTE][] = HDOM_QUOTE_DOUBLE;
        }
        $this->attr[$name] = $value;
    }

    function __isset($name)
    {
        switch($name)
        {
            case 'outertext': return true;
            case 'innertext': return true;
            case 'plaintext': return true;
        }
        //no value attr: nowrap, checked selected...
        return (array_key_exists($name, $this->attr)) ? true : isset($this->attr[$name]);
    }

    function __unset($name)
    {
        if (isset($this->attr[$name]))
            unset($this->attr[$name]);
    }

    function setClass($name)
    {
        $this->classes[]=$name;
    }

    function setAttribute($name, $value)
    {
        $this->__set($name, $value);
    }

    function firstChild()
    {
        return $this->first_child();
    }
}
?>
